import numpy as np
from DATA import DATA
np.random.seed(951105)
def takeSecond(elem):
    return elem[1]
class CROSS(object):
    def __init__(self, id_, north_, east_, south_, west_):
        # **** statistic parameters ****#
        self.id_ = id_
        self.roadIds = [north_, east_, south_, west_]
        self.carport = {} #序号对应发车时间
        self.left=[]
        # absolute loc
        self.x, self.y = 0, 0
        self.mapX,self.mapY = 0,0
        # priorityMap
        self.directionMap = {north_: {east_: 1, south_: 2, west_: -1}, \
                             east_: {south_: 1, west_: 2, north_: -1}, \
                             south_: {west_: 1, north_: 2, east_: -1}, \
                             west_: {north_: 1, east_: 2, south_: -1}}
        # relationship with roads
        self.providerDirection, self.receiverDirection, self.validRoadDirecction = [], [], []

        """
        
        """
        for index, roadId in enumerate(self.roadIds):
            road = DATA.ROADDICT[roadId] if roadId != -1 else None
            if road is not None and (road.__isDuplex__() or road.__to__() == self.id_):
                self.providerDirection.append(index) #将相应方向的路口设置为到达
            if road is not None and (road.__isDuplex__() or road.__from__() == self.id_):
                self.receiverDirection.append(index) #将相应方向的路口设置为出发
            if road is not None:
                self.validRoadDirecction.append(index) #将相应方向的路口设置为不能通过
        #将相应的道路ID 写入是出发站还是终点站，还是空站
        self.provider = [[direction, self.roadIds[direction]] for direction in self.providerDirection]
        self.receiver = [self.roadIds[direction] for direction in self.receiverDirection]
        self.validRoad = [self.roadIds[direction] for direction in self.validRoadDirecction]
        # print("\n\n",self.provider) #[[0, 5104], [2, 5103], [3, 5096]]
        self.provider.sort(key=takeSecond) #[[0, 5102], [2, 5101], [3, 5094]] 变成 [[3, 5094], [2, 5101], [0, 5102]]
        # print(self.provider) #[[3, 5096], [2, 5103], [0, 5104]]
        # print(self.providerDirection) #[0, 2, 3]
        self.providerDirection = [self.provider[i][0] for i in range(self.provider.__len__())] #providerDirection 变成 [3, 2, 0]
        # print(self.providerDirection) #[3, 2, 0]
        self.provider = [self.provider[i][1] for i in range(self.provider.__len__())]
        # print(self.provider) #[5096, 5103, 5104]

        # **** dynamic parameters ****#
        self.readyCars = []
        self.leftCars = []
        self.carportCarNum = 0 ##存储车辆出发站为该路口的车的数量
        self.finishCarNum = 0
        # **** flag ****#
        self.done = False
        self.update = False
    # main functions
    def step(self):
        self.update = False
        for roadId in self.validRoad:
            DATA.ROADDICT[roadId].setBucket(self.id_)
        # data preapre
        nextCarId,nextCar,nextRoad,nextDirection =[],[],[],[]
        #
        # 0,1,2,3 denote north,east,south,west
        #
        """
        寻找所有道路上的最高权限车辆最
        nextDirection进入哪条路的CAR类 self.route的下标， -1 2 
        """
        for index in range(self.provider.__len__()): #便利车辆需要进入交叉路口的道路ID，并且权限是大小是从大到小
            """
            找到这条道路最有优先级权限的车辆,并且记录
            """
            nextCarId.append(DATA.ROADDICT[self.provider[index]].firstPriorityCar())
            # if first priority car exists
            if nextCarId[index]!=-1:#找到了相应道路的最高权限的车辆
                nextCar.append(DATA.CARDICT[nextCarId[index]])#将最高权限的车辆的    类 存到nextCar 里面
                nextRoad.append(nextCar[index].__nextRoad__())#返回下一个将进入哪条路，的ＩＤ的下标
                # nextRoad == -1 => terminal
                if nextRoad[index]==-1:#如果走完了全程，已经没有下条路了，就是这个cross是终点
                    nextDirection.append(2)
                else:
                    nextDirection.append(self.direction(self.provider[index],nextRoad[index]))#存入下条路的ID
            else:#没有找到了最高权限的车辆
                nextCar.append(-1)
                nextRoad.append(-1)
                nextDirection.append(-1)
        # loop
        for presentRoadIndex in range(self.provider.__len__()):
            while nextCar[presentRoadIndex]!=-1:
                #self.provider[presentRoadIndex][5096, 5103, 5104]返回道路ID
                #provider是道路类
                #即将处理的道路
                provider = DATA.ROADDICT[self.provider[presentRoadIndex]]
                for otherRoadIndex in range(self.provider.__len__()):
                    # conflict
                    """
                    第一
                    """
                    if nextCar[otherRoadIndex] != -1 and \
                            self.isConflict(self.providerDirection[presentRoadIndex], nextDirection[presentRoadIndex],
                                            self.providerDirection[otherRoadIndex], nextDirection[otherRoadIndex]):
                        break
                if nextRoad[presentRoadIndex] == -1:
                    nextCar[presentRoadIndex].updateDynamic(3)
                    provider.firstPriorityCarAct(0)
                    DATA.CARDISTRIBUTION[1] -= 1
                    DATA.CARDISTRIBUTION[2] += 1
                    self.finishCarNum += 1
                    self.update = True
                else:
                    nextroad_ = DATA.ROADDICT[nextRoad[presentRoadIndex]]
                    action = nextroad_.receiveCar(nextCar[presentRoadIndex].__id__())
                    if action == 2:
                        # waiting conflict
                        break
                    self.update = True
                    provider.firstPriorityCarAct(action)
                nextCarId[presentRoadIndex] = provider.firstPriorityCar()
                if nextCarId[presentRoadIndex] != -1:
                    nextCar[presentRoadIndex] = DATA.CARDICT[nextCarId[presentRoadIndex]]
                    nextRoad[presentRoadIndex] = nextCar[presentRoadIndex].__nextRoad__()　
                    # nextRoad == -1 => terminal
                    if nextRoad[presentRoadIndex] == -1:
                        nextDirection[presentRoadIndex] = 2
                    else:
                        nextDirection[presentRoadIndex]= self.direction(self.provider[presentRoadIndex], nextRoad[presentRoadIndex])
                else:
                    nextCar[presentRoadIndex] = -1
                    nextRoad[presentRoadIndex]= -1
                    nextDirection[presentRoadIndex] = -1
        done = True
        for fromA in range(self.provider.__len__()):
            if nextCar[fromA] != -1:
                done = False
        self.done = done
    def outOfCarport(self):
        self.readyCars = self.leftCars
        self.leftCars=[]
        if DATA.TIME in self.carport.keys():
            self.carport[DATA.TIME].sort()
            self.readyCars.extend(self.carport[DATA.TIME])
        if self.readyCars.__len__() == 0:
            return
        self.readyCars.sort()
        for roadId in self.receiver:
            DATA.ROADDICT[roadId].setBucket(self.id_)
        for i in range(self.readyCars.__len__()):
            carId = self.readyCars[i]
            roadId = DATA.CARDICT[carId].__nextRoad__()
            road = DATA.ROADDICT[roadId]
            if roadId not in self.receiver:
                print("Car(%d).Road(%d) not in cross(%d).function:class.outOfCarport"%(carId,roadId,self.id_))
            act = road.receiveCar(carId)
            if act!=0:
                self.leftCars.append(self.readyCars[i])
            else:
                self.carportCarNum -= 1
                DATA.CARDISTRIBUTION[0] -= 1
                DATA.CARDISTRIBUTION[1] += 1
    #
    # other functions
    #
    def isConflict(self,fromA,directionA,fromB,directionB):
        # -1,0,1,2,3,4,5 => guard_w,n,e,s,w,guard_n,guard_e
        # -1 ,1, 2 => right left, straight
        # reason why:
        # direction:-1,1,2
        # 0-1=-1=>3=>west,0+1=1=>east,0+2=>2=>south
        # 1-1=0=>north,1+2=2=>south,1+2=3=>west
        # and so...
        #       0
        #   3       1
        #       2
        #
        if (fromA + directionA)%4 == (fromB + directionB)%4 and directionA < directionB:
            return True
        else:
            return False
    def direction(self,providerId,receiverId):#返回两条路转弯的优先级值
        return self.directionMap[providerId][receiverId]
    def setDone(self,bool):#将所有车辆设置为等待状态
        self.done = bool
    def setLoc(self,x,y):
        self.x,self.y = x,y
    def setMapLoc(self,mapX,mapY):
        self.mapX,self.mapY = mapX,mapY
    def roadDirection(self,roadId):
        if self.roadIds[0]==roadId:
            return 0
        elif self.roadIds[1]==roadId:
            return 1
        elif self.roadIds[2]==roadId:
            return 2
        elif self.roadIds[3]==roadId:
            return 3
        else:
            return -1
    def carportInitial(self, timePlan, carId):#仅仅调用一次,存储车辆出发站为该路口的车
        if timePlan not in self.carport.keys():
            self.carport[timePlan] = [carId]
        else:
            self.carport[timePlan].append(carId)
        self.carportCarNum += 1
    #
    # show statistic parameters
    #
    def __id__(self):
        return self.id_
    def __roadIds__(self):
        return self.roadIds
    def __providerDirection__(self):
        return self.providerDirection
    def __receiverDirection__(self):
        return self.receiverDirection
    def __validRoadDirection__(self):
        return self.validRoadDirection
    def __provider__(self):
        return self.provider
    def __receiver__(self):
        return self.receiver
    def __validRoad__(self):
        return self.validRoad
    def __x__(self):
        return self.x
    def __y__(self):
        return self.y
    def __mapX__(self):
        return self.mapX
    def __mapY__(self):
        return self.mapY
    def __done__(self):
        return self.done
    #
    # show dynamic parameters
    #
    def __carportCarNum__(self):
        return self.carportCarNum
    def __finishCarNum__(self):
        return self.finishCarNum
    def __update__(self):
        return self.update
    #
    # show some important info
    #
    def __loc__(self):
        return self.x,self.y
    def __mapLoc__(self):
        return self.mapX,self.mapY